home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 186_01 / make11.c < prev    next >
Text File  |  1985-08-19  |  12KB  |  418 lines

  1. /* MAKE: CP/M version of the UNIX utility.  Compiles and links files
  2.  * as necessary, based on dependancy information in a "makefile".
  3.  * For usage, see MAKE.DOC.
  4.  *
  5.  * This code is an adaptation and expansion of the program "mk" given
  6.  * by Allen Holub in Dr. Dobb's Journal, August 1985 (#106).  
  7.  *
  8.  * To compile:
  9.  *      CC MAKE -E3000
  10.  *      CC MAKEIO -E3000
  11.  *      L2 MAKE MAKEIO
  12.  *
  13.  * If DEBUG is #defined in MAKE.H, then the file MDEBUG.C must be
  14.  * compiled and linked in.
  15.  *
  16.  * CREDITS:
  17.  * 
  18.  * -- dependancies(), tree(), find(), and gmem() functions by 
  19.  *    Allen Holub (DDJ #106).
  20.  * -- main(), make(), and makenode() functions based on code by
  21.  *    Allen Holub (DDJ #106), with significant revisions by
  22.  *    James Pritchett.
  23.  * -- init() and macro() functions by James Pritchett.
  24.  * -- All code by Allen Holub adapted for BDS C (where necessary)
  25.  *    by James Pritchett.
  26.  *
  27.  * Version 1.0 -- 10/28/85
  28.  * Version 1.1 -- 12/06/85
  29.  */
  30.  
  31. #include <bdscio.h>
  32. #include "make.h"
  33.  
  34. #define VERSION "1.1"
  35. #define DATE    "12/06/85"
  36.  
  37. main(argc,argv)
  38. int     argc;
  39. char    **argv;
  40. {
  41.     init(argc,argv);    /* messages, variable initializers, command parsing */
  42.  
  43.     if (fopen(filename,iobuff) == ERROR)    /* Open up the makefile */
  44.         serr("Can't open %s\n",filename);
  45.     if (!dependancies())                    /* Build the object tree */
  46.         err("File empty!\n",0);
  47.     else {
  48.         if (!qopt) {
  49.             printf("Making target object -> %s\n",first);
  50.             printf("Commands needed:\n");
  51.         }
  52.         make(first);                        /* Evaluate all objects */
  53.         if (stackp && !nopt && !topt) {     /* Batch the commands */
  54.             if (!qopt)
  55.                 prompt();
  56.             batch();
  57.         }
  58.         else if (!stackp)
  59.             printf("\tNothing needs making\n");
  60.     }
  61. }
  62.  
  63. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  64.  
  65. void init(argc,argv)    /* Opening message, help message, variable
  66.                          * initialization, and command line parsing.
  67.                          */
  68. int     argc;
  69. char    **argv;
  70. {
  71.     char c;
  72.     int i;
  73.  
  74.     printf("\nMAKE  Version %s   James Pritchett, %s\n\n",VERSION,DATE);
  75.  
  76. /* Answer a cry for help */
  77.  
  78.     if (*argv[1] == '?') {
  79.         printf("Usage: MAKE [target] [-options]\n");
  80.         printf("Makes target or first in file ");
  81.         printf("(if target not specified)\n\n");
  82.         printf("\tOptions:\n");
  83.         printf("\t\t-f filename: Use filename as makefile\n");
  84.         printf("\t\t-a:          Make all targets\n");
  85.         printf("\t\t-n:          Make no targets\n");
  86.         printf("\t\t-q:          Supress all messages\n");
  87.         printf("\t\t-r:          Do not set file attributes\n");
  88.         printf("\t\t-t:          Set file attributes, but do not make\n");
  89.         exit();
  90.     }
  91.  
  92. /* Global variable initialization */
  93.  
  94.     root = NULL;    /* These should be zeroed anyway, */
  95.     first = NULL;   /*    but better safe than sorry  */
  96.     inputline = 0;
  97.     stackp = NULL;
  98.     aopt = nopt = qopt = ropt = topt = FALSE;
  99.     filename = "MAKEFILE";      /* Default filename for makefile */
  100.     defdsk = 0;
  101.     defuser = UNKNOWN;
  102.  
  103. /* Parse the command line, beginning with argv[1] */
  104.  
  105.     i = 1;
  106.  
  107. /* If the first arg is not an option, it must be the target */
  108.  
  109.     if ((--argc) && (*argv[1] != '-')) {
  110.         first = argv[1];
  111.         argc--;
  112.         i++;
  113.     }
  114.  
  115. /* Parse the options */
  116.  
  117.     while (argc--) {
  118.         if (*argv[i] != '-')    /* Ignore anything that ain't an option */
  119.             continue;
  120.         switch (c = *(argv[i++]+1)) {
  121.             case 'A':
  122.                 aopt = TRUE;
  123.                 break;
  124.             case 'N':
  125.                 nopt = TRUE;
  126.                 break;
  127.             case 'Q':
  128.                 qopt = TRUE;
  129.                 break;
  130.             case 'R':
  131.                 ropt = TRUE;
  132.                 break;
  133.             case 'T':
  134.                 topt = TRUE;
  135.                 break;
  136.             case 'F':           /* Alternate makefile name follows */
  137.                 argc--;
  138.                 filename = argv[i++];
  139.                 break;
  140.             default:
  141.                 printf("ERROR: Unknown option -%c ignored.\n",c);
  142.                 break;
  143.         }
  144.     }
  145. }
  146.  
  147. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  148.  
  149. void make(target)       /* Main routine for making.  This function
  150.                          * is recursive: it calls itself if it finds
  151.                          * another object listed in the dependancy_list.
  152.                          */
  153. char *target;   /* Name of object to make */
  154. {
  155.     TNODE   *snode;     /* current target node */
  156.     TNODE   *dnode;     /* dependancy node */
  157.     char    **linev;    /* for handling dependancy vector */
  158.  
  159. #ifdef  DEBUG
  160. debug("DEBUG make: making <%s>\n",target);
  161. #endif
  162.  
  163.  
  164. /* Find the node for this object and abort if not found */
  165.  
  166.     if (!(snode = find(target,root)))
  167.         serr("Don't know how to make <%s>\n",target);
  168.     snode->changed = FALSE;     /* start from unchanged */
  169.  
  170.  
  171. /* Evaluate all the dependancies */
  172.  
  173.     for(linev = snode->depends_on; *linev; linev++) {
  174.  
  175. #ifdef  DEBUG
  176. debug("    DEBUG make: Dependancy = %s\n",*linev);
  177. #endif
  178.  
  179. /* Find the node for the dependancy.  If the dependancy is not
  180.  * in the tree, it must be a file, and should be evaluated and
  181.  * added to the tree.
  182.  */
  183.  
  184.         if (!(dnode = find(*linev,root))) {
  185.             dnode = addfile(*linev);
  186.         }
  187.  
  188. /* If the state of the dependancy is UNKNOWN, then it must be
  189.  * an object that has yet to be made.  If so, then make the
  190.  * dependancy first.
  191.  */
  192.         if (dnode->changed == UNKNOWN) {
  193.             make(*linev);
  194.         }
  195.  
  196. /* If the status of the dependancy is TRUE, then set the object
  197.  * status to TRUE.
  198.  */
  199.         if (dnode->changed) {
  200.             (snode->changed)++;
  201.  
  202. #ifdef  DEBUG
  203. debug("\tDEBUG make (%s): Dependency state TRUE\n",target);
  204. #endif
  205.  
  206.         }
  207.     } /* Close of "for" -- Loop for all dependancies in list. */
  208.  
  209.  
  210. /* If, after evaluating dependancies, the object has been set TRUE,
  211.  * then push the actions onto the stack.  If -a option has been
  212.  * specified, push the actions no matter what the object's state.
  213.  */
  214.     if (snode->changed || aopt) {
  215.  
  216. #ifdef  DEBUG
  217. debug("DEBUG make (%s): Pushing actions\n",target);
  218. #endif
  219.  
  220.         for (linev = snode->do_this; *linev; linev++) {
  221.             if (!qopt)  /* skip the echo if -q is given */
  222.                 printf("\t%s\n",*linev);
  223.             push(*linev);
  224.         }
  225.     }
  226. }
  227.  
  228. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  229.  
  230. int dependancies()  /* Build the objectname tree */
  231. {
  232.     TNODE   *node;
  233.  
  234. /* Set up root of tree */
  235.  
  236.     if (node = makenode()) {
  237.  
  238. /* If a target was not given on the command line, then use the first
  239.  * object in the makefile as the target.
  240.  */
  241.         if (!first)
  242.             first = node->being_made;
  243.         if (!tree(node,&root))
  244.             err("Can't insert first node into tree.\n");
  245.  
  246. /* Makes nodes for all other objects and place into tree. */
  247.  
  248.         while (node = makenode()) {
  249.             if (!tree(node,&root))
  250.                 free(node);
  251.         }
  252.  
  253. #ifdef  DEBUG
  254. printf("DEBUG dependancies: Tree made.\n\n");
  255. trav(root);     /* Print tree */
  256. #endif
  257.  
  258.         fclose(iobuff);
  259.         return TRUE;
  260.     }
  261.     return FALSE;   /* Return FALSE if the makefile is empty */
  262. }
  263.  
  264. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  265.  
  266. int tree(node,rootp)    /* Place a node into the tree.  This function
  267.                          * is recursive, calling itself with the left
  268.                          * or right branches of the tree until it
  269.                          * finds the appropriate spot.
  270.                          */
  271. TNODE   *node;          /* Pointer to node to place in tree */
  272. TNODE   **rootp;        /* Pointer to pointer to current node in 
  273.                          * the tree traversal.
  274.                          */
  275. {